home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / Macintosh Sample Code / SC.013.OOPTESample / UTEDocument.inc1.p < prev    next >
Encoding:
Text File  |  1989-09-30  |  24.8 KB  |  835 lines  |  [TEXT/MPS ]

  1. {---------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple TextEdit Sample Application
  6. #
  7. #    OOPTESample
  8. #
  9. #    UTEDocument.inc1.p        -    Pascal Source
  10. #
  11. #    Copyright © 1988, 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Version:        
  15. #                    1.10                    10/89
  16. #                    1.00                    04/89
  17. #
  18. #    Components:     
  19. #                    BuildOOPTESample        October 1, 1989
  20. #                    MOOPTESample.p            October 1, 1989
  21. #                    OOPTESample.make        October 1, 1989
  22. #                    TECommon.h                October 1, 1989
  23. #                    TESampleGlue.a            October 1, 1989
  24. #                    TESample.r                October 1, 1989
  25. #                    UApplication.p            October 1, 1989
  26. #                    UApplication.inc1.p        October 1, 1989
  27. #                    UDocument.p                October 1, 1989
  28. #                    UDocument.inc1.p        October 1, 1989
  29. #                    UTEDocument.p            October 1, 1989
  30. #                    UTEDocument.inc1.p        October 1, 1989
  31. #                    UTESample.p                October 1, 1989
  32. #                    UTESample.inc1.p        October 1, 1989
  33. #
  34. ---------------------------------------------------------------------}
  35.  
  36. CONST
  37.     kTextMargin                = 2;    {kTextMargin is the number of pixels we leave
  38.                                     blank at the edge of the window.}
  39.  
  40.     kMaxDocWidth            = 576;    {kMaxDocWidth is an arbitrary number used to specify
  41.                                     the width of the TERec's destination rectangle so that
  42.                                     word wrap and horizontal scrolling can be demonstrated.}
  43.  
  44.  
  45.     kMinDocDim                = 64;    {kMinDocDim is used to limit the minimum dimension
  46.                                     of a window when GrowWindow is called.}
  47.  
  48.  
  49.     kControlInvisible        = 0;
  50.     kControlVisible            = $FF;    {kControlInvisible is used to 'turn off' controls
  51.                                     (i.e., cause the control not to be redrawn as a result
  52.                                     of some Control Manager call such as SetCtlValue)
  53.                                     by being put into the contrlVis field of the record.
  54.                                     kControlVisible is used the same way to 'turn on'
  55.                                     the control.}
  56.  
  57.     kScrollbarWidth            = 16;    {kScrollBarAdjust and kScrollBarWidth are used in
  58.                                     calculating values for control positioning and sizing.}
  59.     kScrollbarAdjust        = kScrollbarWidth - 1;
  60.     kGrowboxAdjust             = 15;
  61.  
  62.     kScrollTweek            = 2;    {kScrollTweek compensates for off-by-one requirements
  63.                                     of the scrollbars to have borders coincide with the
  64.                                     growbox.}
  65.  
  66.     kCRChar                    = chr(13);
  67.     kDelChar                = chr(8);    {kCrChar is used to match with a carriage return
  68.                                     when calculating the number of lines in the TextEdit
  69.                                     record. kDelChar is used to check for delete in
  70.                                     keyDowns.}
  71.  
  72.     kButtonScroll            = 4;    {kButtonScroll is how many pixels to scroll horizontally
  73.                                     when the button part of the horizontal scrollbar is
  74.                                     pressed.}
  75.  
  76.  
  77.     kMaxTELength            = 32000;    {kMaxTELength is an arbitrary number used to limit
  78.                                     the length of text in the TERec so that various errors
  79.                                     won't occur from too many characters in the text.}
  80.  
  81.     kTESlop                    = 1024;    { provides some extra security when pre-flighting
  82.                                     edit commands. }
  83.  
  84.     rVScroll                = 128;    { vertical scrollbar control }
  85.     rHScroll                = 129;    { horizontal scrollbar control }
  86.  
  87.     kTEDocErrStrings         = 129;    { id of our STR# for error strings }
  88.  
  89.     { The following are indicies into STR# resources. }
  90.     eNoMemory                = 1;
  91.     eNoSpaceCut                = 2;
  92.     eNoCut                    = 3;
  93.     eNoCopy                    = 4;
  94.     eExceedPaste            = 5;
  95.     eNoSpacePaste            = 6;
  96.     eNoWindow                = 7;
  97.     eExceedChar                = 8;
  98.     eNoPaste                = 9;
  99.  
  100. (********************************************************************************************)
  101. (*        G l o b a l   R o u t i n e s                                                        *)
  102. (********************************************************************************************)
  103. (*
  104.     Routines used by this class, which don't belong to the class since we use
  105.     them as toolbox filter routines, and you cannot pass class methods as ProcPtrs.
  106. *)
  107.  
  108.  
  109. PROCEDURE AsmClikLoop; EXTERNAL;
  110.  
  111. { Common algorithm for pinning the value of a control. It returns the actual amount }
  112. { the value of the control changed. }
  113.  
  114. {$S Main}
  115. PROCEDURE CommonAction(control:ControlHandle; VAR amount:integer);
  116. VAR
  117.     value, max: integer;
  118. BEGIN
  119.     value := GetCtlValue(control);
  120.     max := GetCtlMax(control);
  121.     amount := value - amount;
  122.     IF (amount <= 0) THEN
  123.         amount := 0
  124.     ELSE IF (amount >= max) THEN
  125.         amount := max;
  126.     SetCtlValue(control, amount);
  127.     amount := value - amount;   { calculate true change }
  128. END; { CommonAction  }
  129.  
  130.  
  131. { Determines how much to change the value of the vertical scrollbar by and how }
  132. { much to scroll the TE record.}
  133.  
  134. {$S Main}
  135. PROCEDURE VActionProc(control:ControlHandle;part:integer);
  136. VAR
  137.     amount:integer;
  138.     window:WindowPtr;
  139.     hTE:TEHandle;
  140.     doc:TTEDocument;
  141. BEGIN
  142.     IF (part <> 0) THEN BEGIN
  143.         window := control^^.contrlOwner;
  144.         doc := TTEDocument(gApplication.DocList.FindDoc(window));
  145.         hTE := doc.GetTEHandle;
  146.         CASE part OF
  147.             inUpButton, inDownButton:        { one line  }
  148.                 amount := 1;
  149.             inPageUp, inPageDown:            { one page  }
  150.                 WITH hTE^^,viewRect DO
  151.                     amount := (bottom - top) DIV lineHeight;
  152.         END;
  153.         IF ((part = inDownButton) OR (part = inPageDown)) THEN
  154.             amount := -amount;        { reverse direction for a downer  }
  155.         CommonAction(control, amount);
  156.         IF (amount <> 0) THEN
  157.             TEScroll(0, amount*hTE^^.lineHeight, hTE);
  158.     END;
  159. END; { VActionProc }
  160.  
  161. { Determines how much to change the value of the horizontal scrollbar by and how }
  162. { much to scroll the TE record. }
  163.  
  164. {$S Main}
  165. PROCEDURE HActionProc(control:ControlHandle;part:integer);
  166. VAR
  167.     amount:integer;
  168.     window:WindowPtr;
  169.     hTE:TEHandle;
  170.     doc:TTEDocument;
  171. BEGIN
  172.     IF (part <> 0) THEN BEGIN
  173.         window := control^^.contrlOwner;
  174.         doc := TTEDocument(gApplication.DocList.FindDoc(window));
  175.         hTE := doc.GetTEHandle;
  176.         CASE part OF
  177.             inUpButton, inDownButton:        { a few pixels }
  178.                 amount := kButtonScroll;
  179.             inPageUp, inPageDown:            { a page width }
  180.                 WITH hTE^^.viewRect DO
  181.                     amount := (right - left);
  182.         END;
  183.         IF ((part = inDownButton) OR (part = inPageDown)) THEN
  184.             amount := -amount;        { reverse direction }
  185.         CommonAction(control, amount);
  186.         IF (amount <> 0) THEN
  187.             TEScroll(amount, 0, hTE);
  188.     END;
  189. END; { HActionProc }
  190.  
  191. { Gets called from our assembly language routine, AsmClikLoop, which in turn }
  192. { is called by the TEClick toolbox routine. Saves the window's clip region, }
  193. { sets it to the portRect, adjusts the scrollbar values to match the TE scroll }
  194. { amount, then restores the clip region. }
  195.  
  196. {$S Main}
  197. PROCEDURE PascalClikLoop;
  198. VAR
  199.     region: RgnHandle;
  200.     wind: WindowPtr;
  201.     doc: TTEDocument;
  202. BEGIN
  203.     wind := FrontWindow;
  204.     doc := TTEDocument(gApplication.DocList.FindDoc(wind));
  205.     region := NewRgn;
  206.     GetClip(region);                { save the old clip }
  207.     ClipRect(wind^.portRect);        { set the new clip }
  208.     doc.AdjustScrollValues(FALSE);    { pass false for canRedraw }
  209.     SetClip(region);                { restore the old clip }
  210.     DisposeRgn(region);
  211. END; { PascalClikLoop }
  212.  
  213. { Gets called from our assembly language routine, AsmClikLoop, which is in }
  214. { turn called by the TEClick toolbox routine. It returns the address of the }
  215. { default clikLoop routine that was put into the TERec by TEAutoView to }
  216. { AsmClikLoop so that it can call it. }
  217.  
  218. {$S Main}
  219. FUNCTION GetOldClikLoop:ProcPtr;
  220. VAR
  221.     doc: TTEDocument;
  222. BEGIN
  223.     doc := TTEDocument(gApplication.DocList.FindDoc(FrontWindow));
  224.     IF (doc = NIL) THEN
  225.         GetOldClikLoop := nil
  226.     ELSE
  227.         GetOldClikLoop := doc.GetClikLoop;
  228. END; { GetOldClikLoop }
  229.  
  230.  
  231. (********************************************************************************************)
  232. (*        T T E D o c u m e n t                                                                *)
  233. (********************************************************************************************)
  234.  
  235. {$S Initialize}
  236. {-----------------------------------+
  237. |    ITEDocument                        |
  238. +-----------------------------------}
  239. PROCEDURE TTEDocument.ITEDocument(resID:integer);
  240. VAR
  241.     good:Boolean;
  242.     destRect, viewRect: Rect;
  243. BEGIN
  244.  
  245.     IDocument(resID);
  246.  
  247.     SetPort(fDocWindow);
  248.     GetTERect(viewRect);
  249.     destRect := viewRect;
  250.     destRect.right := destRect.left + kMaxDocWidth;
  251.     fDocTE := TENew(destRect, viewRect);
  252.  
  253.     good := (fDocTE <> NIL);        { if TENew succeeded, we have a good document. }
  254.     IF good THEN BEGIN                { good document? — get scrollbars  }
  255.         AdjustViewRect;
  256.         TEAutoView(TRUE, fDocTE);
  257.         fDocClik := fDocTE^^.clikLoop;
  258.         fDocTE^^.clikLoop := @AsmClikLoop;
  259.         fDocVScroll := GetNewControl(rVScroll, fDocWindow);
  260.         good := (fDocVScroll <> NIL);
  261.     END;
  262.     IF good THEN BEGIN
  263.         fDocHScroll := GetNewControl(rHScroll, fDocWindow);
  264.         good := (fDocHScroll <> NIL);
  265.     END;
  266.  
  267.     IF good THEN BEGIN                { good? — adjust & draw the controls, draw the window }
  268.         AdjustScrollValues(FALSE);
  269.         ShowWindow(fDocWindow);
  270.     END ELSE BEGIN                    { tell user we failed }
  271.         AlertUser(kTEDocErrStrings,eNoWindow);
  272.     END;
  273. END;
  274.  
  275. {$S Main}
  276. {-----------------------------------+
  277. |    Free                            |
  278. +-----------------------------------}
  279. PROCEDURE TTEDocument.Free; OVERRIDE;
  280. BEGIN
  281.     HideWindow(fDocWindow);
  282.     IF fDocTE <> NIL THEN
  283.       TEDispose(fDocTE);            { dispose the TEHandle if we got far enough to make one  }
  284.     IF fDocVScroll <> NIL THEN
  285.       DisposeControl(fDocVScroll);
  286.     IF fDocHScroll <> NIL THEN
  287.       DisposeControl(fDocHScroll);
  288.     INHERITED Free;
  289. END;
  290.  
  291. {$S Main}
  292. {-----------------------------------+
  293. |    DoZoom                            |
  294. +-----------------------------------}
  295. PROCEDURE TTEDocument.DoZoom(partCode:integer); OVERRIDE;
  296. BEGIN
  297.     EraseRect(fDocWindow^.portRect);
  298.     ZoomWindow(fDocWindow, partCode, (fDocWindow = FrontWindow));
  299.     ResizeWindow;    {after this, only thing valid is scrollbars.}
  300. END;
  301.  
  302. {$S Main}
  303. {-----------------------------------+
  304. |    DoGrow                            |
  305. +-----------------------------------}
  306.  
  307. {Called when a mouseDown occurs in the grow box of an active window. In
  308.  order to eliminate any 'flicker', we want to invalidate only what is
  309.  necessary. Since ResizeWindow invalidates the whole portRect, we save
  310.  the old TE viewRect, intersect it with the new TE viewRect, and
  311.  remove the result from the update region. However, we must make sure
  312.  that any old update region that might have been around gets put back.}
  313.  
  314. PROCEDURE TTEDocument.DoGrow(theEvent:EventRecord); OVERRIDE;
  315. VAR
  316.     growResult: longint;
  317.     tempRect:    Rect;
  318.     tempRgn:    RgnHandle;
  319.     
  320.     PROCEDURE GetLocalUpdateRgn(aRgn:RgnHandle);
  321.     BEGIN
  322.         CopyRgn(WindowPeek(fDocWindow)^.updateRgn, aRgn);    {save old update region}
  323.         WITH fDocWindow^.portBits.bounds DO
  324.             OffsetRgn(aRgn, left, top);                        {convert to local coords}
  325.     END;
  326.  
  327. BEGIN
  328.     tempRect := screenBits.bounds;
  329.     tempRect.left := kMinDocDim;
  330.     tempRect.top := kMinDocDim;
  331.     growResult := GrowWindow(fDocWindow, theEvent.where, tempRect);
  332.     { see if it really changed size  }
  333.     IF growResult <> 0 THEN BEGIN
  334.         tempRect := fDocTE^^.viewRect;
  335.         tempRgn := NewRgn;
  336.         GetLocalUpdateRgn(tempRgn);
  337.         SizeWindow(fDocWindow, LoWrd(growResult), HiWrd(growResult), TRUE);
  338.         ResizeWindow;    {after this, only thing valid is scrollbars.}
  339.         IF SectRect(tempRect, fDocTE^^.viewRect, tempRect) THEN;
  340.         ValidRect(tempRect);
  341.         InvalRgn(tempRgn);
  342.         DisposeRgn(tempRgn);
  343.     END;
  344. END;
  345.  
  346. {$S Main}
  347. {-----------------------------------+
  348. |    DoContent                        |
  349. +-----------------------------------}
  350. PROCEDURE TTEDocument.DoContent(theEvent:EventRecord); OVERRIDE;
  351. VAR
  352.     mouse:        Point;
  353.     control:    ControlHandle;
  354.     part,value:    integer;
  355.     shiftDown:    Boolean;
  356. BEGIN
  357.     SetPort(fDocWindow);
  358.     mouse := theEvent.where;            { get the click position  }
  359.     GlobalToLocal(mouse);
  360.     part := FindControl(mouse, fDocWindow, control);
  361.     CASE part OF
  362.           0: BEGIN                        { not in a control }
  363.             { see if we need to extend the selection  }
  364.             shiftDown := BAnd(theEvent.modifiers, shiftKey) <> 0;    { extend if Shift is down  }
  365.             TEClick(mouse, shiftDown, fDocTE);
  366.         END;
  367.         inThumb: BEGIN
  368.             value := GetCtlValue(control);
  369.             part := TrackControl(control, mouse, NIL);
  370.             IF part <> 0 THEN BEGIN
  371.                 value := value - GetCtlValue(control);
  372.                 { value now has CHANGE in value; if value changed, scroll  }
  373.                 IF value <> 0 THEN BEGIN
  374.                     IF control = fDocVScroll THEN BEGIN
  375.                         TEScroll(0, value * fDocTE^^.lineHeight, fDocTE);
  376.                     END ELSE BEGIN
  377.                         TEScroll(value, 0, fDocTE);
  378.                     END;
  379.                 END;
  380.             END;
  381.         END;
  382.         OTHERWISE BEGIN                        { they clicked in an arrow, so track & scroll  }
  383.             IF control = fDocVScroll THEN BEGIN
  384.                 value := TrackControl(control, mouse, @VActionProc);
  385.             END ELSE BEGIN
  386.                 value := TrackControl(control, mouse, @HActionProc);
  387.             END;
  388.         END;
  389.     END;
  390. END;
  391.  
  392. {$S Main}
  393. {-----------------------------------+
  394. |    DoKeyDown                        |
  395. +-----------------------------------}
  396. PROCEDURE TTEDocument.DoKeyDown(theEvent:EventRecord); OVERRIDE;
  397. VAR
  398.     key: char;
  399. BEGIN
  400.     IF BAnd(theEvent.modifiers, cmdKey) <> 1 THEN BEGIN    { don't process command characters }
  401.         key := char(BAnd(theEvent.message, charCodeMask));
  402.         { we have a char. for our window; see if we are still below TextEdit’s }
  403.         { limit for the number of characters }
  404.         WITH fdocTE^^ DO BEGIN
  405.             IF ((key = kDelChar) OR ((teLength - selEnd - selStart) + 1 < kMaxTELength)) THEN BEGIN
  406.                 TEKey(key, fDocTE);
  407.                 AdjustScrollbars(FALSE);
  408.                 AdjustTE;
  409.             END ELSE BEGIN
  410.                 AlertUser(kTEDocErrStrings,eExceedChar);
  411.             END;
  412.         END;
  413.     END;
  414. END;
  415.  
  416. {$S Main}
  417. {-----------------------------------+
  418. |    DoActivate                        |
  419. +-----------------------------------}
  420. PROCEDURE TTEDocument.DoActivate(becomingActive:Boolean); OVERRIDE;
  421. VAR
  422.     tempRgn:    RgnHandle;
  423.     clipRgn:    RgnHandle;
  424.     growRect:    Rect;
  425. BEGIN
  426.     IF becomingActive THEN BEGIN
  427.  
  428.         { since we don’t want TEActivate to draw a selection in an area where }
  429.         { we’re going to erase and redraw, we’ll clip out the update region }
  430.         { before calling it. }
  431.         tempRgn := NewRgn;
  432.         clipRgn := NewRgn;
  433.         { save old update region }
  434.         CopyRgn(WindowPeek(fDocWindow)^.updateRgn, tempRgn);
  435.         { put it in local coords }
  436.         WITH fDocWindow^.portBits.bounds DO
  437.             OffsetRgn(tempRgn, left, top);
  438.         GetClip(clipRgn);
  439.         { subtract updateRgn from clipRgn }
  440.         DiffRgn(clipRgn, tempRgn, tempRgn);
  441.         { make it the new clipRgn }
  442.         SetClip(tempRgn);
  443.         TEActivate(fDocTE);
  444.         { restore the full-blown clipRgn }
  445.         SetClip(clipRgn);
  446.         { get rid of temp regions }
  447.         DisposeRgn(tempRgn);
  448.         DisposeRgn(clipRgn);
  449.  
  450.         { the controls must be redrawn on activation: }
  451.         fDocVScroll^^.contrlVis := kControlVisible;
  452.         fDocHScroll^^.contrlVis := kControlVisible;
  453.         InvalRect(fDocVScroll^^.contrlRect);
  454.         InvalRect(fDocHScroll^^.contrlRect);
  455.         { the growbox needs to be redrawn on activation: }
  456.         growRect := fDocWindow^.portRect;
  457.         { adjust for the scrollbars }
  458.         WITH growRect DO BEGIN
  459.             top := bottom - kScrollbarAdjust;
  460.             left := right - kScrollbarAdjust;
  461.         END;
  462.         InvalRect(growRect);
  463.     END ELSE BEGIN                { becoming Inactive }
  464.         TEDeactivate(fDocTE);
  465.         { the controls must be hidden on deactivation: }
  466.         HideControl(fDocVScroll);
  467.         HideControl(fDocHScroll);
  468.         { we draw grow icon immediately, since we deactivate controls }
  469.         { immediately, and the update delay looks funny }
  470.         DrawGrowIcon(fDocWindow);
  471.     END;
  472. END;
  473.  
  474. {$S Main}
  475. {-----------------------------------+
  476. |    DoIdle                            |
  477. +-----------------------------------}
  478. PROCEDURE TTEDocument.DoIdle; OVERRIDE;
  479. BEGIN
  480.     TEIdle(fDocTE);
  481. END;
  482.  
  483. {$S Main}
  484. {-----------------------------------+
  485. |    DoUpdate                        |
  486. +-----------------------------------}
  487. PROCEDURE TTEDocument.DoUpdate; OVERRIDE;
  488. BEGIN
  489.     BeginUpdate(fDocWindow);                    { this sets up the visRgn }
  490.     IF NOT EmptyRgn(fDocWindow^.visRgn) THEN    { draw if updating needs to be done }
  491.         DrawWindow;
  492.     EndUpdate(fDocWindow);
  493. END;
  494.  
  495. {$S Main}
  496. {-----------------------------------+
  497. |    DoCut                            |
  498. +-----------------------------------}
  499. PROCEDURE TTEDocument.DoCut; OVERRIDE;
  500. VAR
  501.     total, contig:    longint;
  502. BEGIN
  503.     IF (ZeroScrap = noErr) THEN BEGIN
  504.         PurgeSpace(total, contig);
  505.         IF (fDocTE^^.selEnd - fDocTE^^.selStart + kTESlop > contig) THEN BEGIN
  506.             AlertUser(kTEDocErrStrings,eNoSpaceCut);
  507.         END ELSE BEGIN
  508.             TECut(fDocTE);
  509.             IF (TEToScrap <> noErr) THEN BEGIN
  510.                 AlertUser(kTEDocErrStrings,eNoCut);
  511.                 IF Boolean(ZeroScrap) THEN;
  512.             END;
  513.         END;
  514.     END;
  515.     AdjustScrollbars(FALSE);
  516.     AdjustTE;
  517. END;
  518.  
  519. {$S Main}
  520. {-----------------------------------+
  521. |    DoCopy                            |
  522. +-----------------------------------}
  523. PROCEDURE TTEDocument.DoCopy; OVERRIDE;
  524. BEGIN
  525.     IF (ZeroScrap = noErr) THEN BEGIN
  526.         TECopy(fDocTE);                { after copying, export the TE scrap }
  527.         IF (TEToScrap <> noErr) THEN BEGIN
  528.             AlertUser(kTEDocErrStrings,eNoCopy);
  529.             IF Boolean(ZeroScrap) THEN;
  530.         END;
  531.     END;
  532.     AdjustScrollbars(FALSE);
  533.     AdjustTE;
  534. END;
  535.  
  536. {$S Main}
  537. {-----------------------------------+
  538. |    DoPaste                            |
  539. +-----------------------------------}
  540. PROCEDURE TTEDocument.DoPaste; OVERRIDE;
  541. VAR
  542.     aHandle:    Handle;
  543.     oldsize,
  544.     newSize:    longint;
  545.     saveErr:    OSErr;
  546. BEGIN
  547.     IF (TEFromScrap = noErr) THEN BEGIN
  548.         WITH fDocTE^^ DO BEGIN
  549.             IF (TEGetScrapLen + (teLength - (selEnd - selStart)) > kMaxTELength) THEN BEGIN
  550.                 AlertUser(kTEDocErrStrings,eExceedPaste);
  551.             END ELSE BEGIN
  552.                 aHandle := Handle(TEGetText(fDocTE));
  553.                 oldSize := GetHandleSize(aHandle);
  554.                 newSize := oldSize + TEGetScrapLen + kTESlop;
  555.                 SetHandleSize(aHandle, newSize);
  556.                 saveErr := MemError;
  557.                 SetHandleSize(aHandle, oldSize);
  558.                 IF (saveErr <> noErr) THEN BEGIN
  559.                     AlertUser(kTEDocErrStrings,eNoSpacePaste);
  560.                 END ELSE BEGIN
  561.                     TEPaste(fDocTE);
  562.                 END;
  563.             END;
  564.         END;
  565.     END ELSE BEGIN
  566.         AlertUser(kTEDocErrStrings,eNoPaste);
  567.     END;
  568.     AdjustScrollbars(FALSE);
  569.     AdjustTE;
  570. END;
  571.  
  572. {$S Main}
  573. {-----------------------------------+
  574. |    DoClear                            |
  575. +-----------------------------------}
  576. PROCEDURE TTEDocument.DoClear; OVERRIDE;
  577. BEGIN
  578.     TEDelete(fDocTE);
  579.     AdjustScrollbars(FALSE);
  580.     AdjustTE;
  581. END;
  582.  
  583. {$S Main}
  584. {-----------------------------------+
  585. |    HaveSelection                    |
  586. +-----------------------------------}
  587. FUNCTION TTEDocument.HaveSelection:Boolean; OVERRIDE;
  588. BEGIN
  589.     IF (fDocTE^^.selStart < fDocTE^^.selEnd) THEN
  590.         HaveSelection := TRUE
  591.     ELSE
  592.         HaveSelection := FALSE;
  593. END;
  594.  
  595. {$S Main}
  596. {-----------------------------------+
  597. |    CalcIdle                        |
  598. +-----------------------------------}
  599. FUNCTION TTEDocument.CalcIdle:Longint; OVERRIDE;
  600. BEGIN
  601.     IF NOT(HaveSelection) THEN BEGIN
  602.         CalcIdle := GetCaretTime;
  603.     END ELSE BEGIN
  604.         CalcIdle := $7FFFFFFF;
  605.     END;
  606. END;
  607.  
  608. {$S Main}
  609. {-----------------------------------+
  610. |    AdjustScrollValues                |
  611. +-----------------------------------}
  612. { Simply call the common adjust routine for the vertical and horizontal scrollbars. }
  613. PROCEDURE TTEDocument.AdjustScrollValues(mustRedraw:Boolean);
  614. BEGIN
  615.     AdjustHV(true, mustRedraw);
  616.     AdjustHV(false, mustRedraw);
  617. END;
  618.  
  619. {$S Main}
  620. {-----------------------------------+
  621. |    GetClikLoop                        |
  622. +-----------------------------------}
  623. FUNCTION TTEDocument.GetClikLoop:ProcPtr;
  624. BEGIN
  625.     GetClikLoop := fDocClik;
  626. END;
  627.  
  628. {$S Main}
  629. {-----------------------------------+
  630. |    GetTEHandle                        |
  631. +-----------------------------------}
  632. FUNCTION TTEDocument.GetTEHandle:TEHandle;
  633. BEGIN
  634.     GetTEHandle := fDocTE;
  635. END;
  636.  
  637. {$S Main}
  638. {-----------------------------------+
  639. |    GetVisTERgn                        |
  640. +-----------------------------------}
  641. PROCEDURE TTEDocument.GetVisTERgn(rgn:RgnHandle);
  642. VAR
  643.     teRect:    Rect;
  644. BEGIN
  645.     teRect := fDocTE^^.viewRect;        { get a local copy of viewRect }
  646.     SetPort(fDocWindow);            { make sure we have right port }
  647.     LocalToGlobal(teRect.topLeft);
  648.     LocalToGlobal(teRect.botRight);
  649.     RectRgn(rgn, teRect);
  650.     { we temporarily change the port’s origin to “globalfy” the visRgn }
  651.     WITH fDocWindow^.portbits.bounds DO
  652.         SetOrigin(-left,-top);
  653.     SectRgn(rgn, fDocWindow^.visRgn, rgn);
  654.     SetOrigin(0, 0);
  655. END;
  656.  
  657. {$S Main}
  658. {-----------------------------------+
  659. |    GetTERect                        |
  660. +-----------------------------------}
  661. { Return a rectangle that is inset from the portRect by the size of }
  662. { the scrollbars and a little extra margin. }
  663. PROCEDURE TTEDocument.GetTERect(VAR teRect:Rect);
  664. BEGIN
  665.     teRect := fDocWindow^.portRect;
  666.     InsetRect(teRect, kTextMargin, kTextMargin);        { adjust for margin  }
  667.     WITH teRect DO BEGIN
  668.         bottom := bottom - kScrollbarAdjust;            { and for the scrollbars }
  669.         right := right - kScrollbarAdjust;
  670.     END;
  671. END;
  672.  
  673. {$S Main}
  674. {-----------------------------------+
  675. |    AdjustTE                        |
  676. +-----------------------------------}
  677. { Scroll the TERec around to match up to the potentially updated scrollbar }
  678. { values. This is really useful when the window has been resized such that the }
  679. { scrollbars became inactive but the TERec was already scrolled. }
  680. PROCEDURE TTEDocument.AdjustTE;
  681. BEGIN
  682.     WITH fDocTE^^ DO BEGIN
  683.         TEScroll((viewRect.left - destRect.left) - GetCtlValue(fDocHScroll),
  684.                  (viewRect.top - destRect.top) - (GetCtlValue(fDocVScroll) * lineHeight),
  685.                  fDocTE);
  686.     END;
  687. END;
  688.  
  689. {$S Main}
  690. {-----------------------------------+
  691. |    DrawWindow                        |
  692. +-----------------------------------}
  693. PROCEDURE TTEDocument.DrawWindow;
  694. BEGIN
  695.     SetPort(fDocWindow);
  696.     EraseRect(fDocWindow^.portRect);    { As per TextEdit chapter of Inside Macintosh }
  697.     DrawControls(fDocWindow);            { This ordering makes for a better appearance }
  698.     DrawGrowIcon(fDocWindow);
  699.     TEUpdate(fDocWindow^.portRect, fDocTE);
  700. END;
  701.  
  702. {$S Main}
  703. {-----------------------------------+
  704. |    AdjustViewRect                    |
  705. +-----------------------------------}
  706. { Update the TERec's view rect so that it is the greatest multiple of }
  707. { the lineHeight that still fits in the old viewRect. }
  708. PROCEDURE TTEDocument.AdjustViewRect;
  709. BEGIN
  710.     WITH fDocTE^^,fDocTE^^.viewRect DO BEGIN
  711.         bottom := (((bottom - top) DIV lineHeight) * lineHeight) + top;
  712.     END;
  713. END;
  714.  
  715. {$S Main}
  716. {-----------------------------------+
  717. |    ResizeWindow                    |
  718. +-----------------------------------}
  719.  
  720. {Called when the window has been resized to fix up the controls and content.
  721.  This routine moves and resizes the scrollbars, adjusts their values, scrolls
  722.  the TERecord in case we grew the window out from under it, invalidates the
  723.  entire port, and then validates the areas under the scrollbars.}
  724.  
  725. PROCEDURE TTEDocument.ResizeWindow;
  726. BEGIN
  727.     AdjustScrollbars(TRUE);                { adjust, redraw anyway  }
  728.     AdjustTE;
  729.     InvalRect(fDocWindow^.portRect);    { invalidate the whole content  }
  730.     { the scrollbars were taken care of by AdjustScrollbars, so validate ’em  }
  731.     ValidRect(fDocVScroll^^.contrlRect);
  732.     ValidRect(fDocHScroll^^.contrlRect);
  733. END;
  734.  
  735. {$S Main}
  736. {-----------------------------------+
  737. |    AdjustHV                        |
  738. +-----------------------------------}
  739. { Calculate the new control maximum value and current value, whether it is the horizontal or }
  740. { vertical scrollbar. The vertical max is calculated by comparing the number of lines to the }
  741. { vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document }
  742. { width to the width of the viewRect. The current values are set by comparing the offset between }
  743. { the view and destination rects. If necessary, redraw the control by calling ShowControl. }
  744. PROCEDURE TTEDocument.AdjustHV(isVert, mustRedraw:Boolean);
  745. VAR
  746.     value, lines, max:    integer;
  747.     oldValue, oldMax:    integer;
  748.     hTE:                TEHandle;
  749.     control:            ControlHandle;
  750. BEGIN
  751.     IF isVert THEN
  752.         control := fDocVScroll
  753.     ELSE
  754.         control := fDocHScroll;
  755.     oldValue := GetCtlValue(control);
  756.     oldMax := GetCtlMax(control);
  757.     hTE := fDocTE;
  758.     WITH hTE^^ DO BEGIN
  759.         IF isVert THEN BEGIN
  760.             lines := nLines;
  761.             { since nLines isn’t right if the last character is a return, check for that case }
  762.             { MUST perform a short circuit check here, or we get a check error. }
  763.             IF ((teLength > 0) & (CharsHandle(hText)^^[teLength-1] = kCrChar)) THEN
  764.                 lines := lines + 1;
  765.             WITH viewRect DO max := lines - ((bottom - top) DIV lineHeight);
  766.         END    ELSE BEGIN
  767.             WITH viewRect DO max := kMaxDocWidth - (right - left);
  768.         END;
  769.     END;
  770.     IF max < 0 THEN max := 0;
  771.     SetCtlMax(control, max);
  772.     
  773.     WITH hTE^^ DO BEGIN
  774.         IF isVert THEN BEGIN
  775.             value := (viewRect.top - destRect.top) DIV lineHeight
  776.         END ELSE BEGIN
  777.             value := viewRect.left - destRect.left;
  778.         END;
  779.     END;
  780.     
  781.     {Pin the value to within range}
  782.     IF value < 0 THEN value := 0;
  783.     IF value > max THEN value := max;
  784.     
  785.     SetCtlValue(control, value);
  786.     { now redraw the control if asked to or if a setting changed  }
  787.     IF ((mustRedraw) OR ((max <> oldMax) OR (value <> oldValue))) THEN
  788.         ShowControl(control);
  789. END;
  790.  
  791. {$S Main}
  792. {-----------------------------------+
  793. |    AdjustScrollSizes                |
  794. +-----------------------------------}
  795. { Re-calculate the position and size of the viewRect and the scrollbars. }
  796. { kScrollTweek compensates for off-by-one requirements of the scrollbars }
  797. { to have borders coincide with the growbox. }
  798. PROCEDURE TTEDocument.AdjustScrollSizes;
  799. VAR
  800.     teRect:    Rect;
  801. BEGIN    
  802.     GetTERect(teRect);
  803.     fDocTE^^.viewRect := teRect;
  804.     AdjustViewRect;
  805.     WITH fDocWindow^.portRect DO BEGIN
  806.         MoveControl(fDocVScroll, right - kScrollbarAdjust, -1);
  807.         SizeControl(fDocVScroll, kScrollbarWidth, bottom - top - kGrowboxAdjust + kScrollTweek);
  808.         MoveControl(fDocHScroll, -1, bottom - kScrollbarAdjust);
  809.         SizeControl(fDocHScroll, right - left - kGrowboxAdjust + kScrollTweek, kScrollbarWidth);
  810.     END;
  811. END;
  812.  
  813. {$S Main}
  814. {-----------------------------------+
  815. |    AdjustScrollbars                |
  816. +-----------------------------------}
  817. { Turn off the controls by jamming a zero into their contrlVis fields (HideControl erases them }
  818. { and we don't want that). If the controls are to be resized as well, call the procedure to do that, }
  819. { then call the procedure to adjust the maximum and current values. Finally re-enable the controls }
  820. { by jamming a $FF in their contrlVis fields (ShowControl re-draws the control, which may not be }
  821. { necessary). }
  822. PROCEDURE TTEDocument.AdjustScrollbars(needsResize:Boolean);
  823. BEGIN
  824.     { First, turn visibility of scrollbars off so we won’t get unwanted redrawing  }
  825.     fDocVScroll^^.contrlVis := kControlInvisible;
  826.     fDocHScroll^^.contrlVis := kControlInvisible;
  827.     IF needsResize THEN BEGIN
  828.         AdjustScrollSizes;
  829.     END;
  830.     AdjustScrollValues(needsResize);
  831.     { Now, restore visibility in case we never had to draw during adjustment  }
  832.     fDocVScroll^^.contrlVis := kControlVisible;
  833.     fDocHScroll^^.contrlVis := kControlVisible;
  834. END;
  835.